/**
 * 获取数据类型
 *
 * getType([]) -> "[object Array]"
 *
 * @param target
 * @returns {string}
 */
function toRawType (target) {
  return Object.prototype.toString.call(target)
}

/**
 * 获取对象的数据类型
 *
 * getType([]) -> "array"
 *
 * @param target 目标对象
 * @returns {string}
 */
function getType (target) {
  return toRawType(target).slice(8, -1).toLowerCase()
}

/**
 * 获取对象的数据类型
 *
 * getType([], "array") -> true
 *
 * @param target 目标对象
 * @param { string } type 目标类型
 * @returns { boolean }
 */
function isType (target, type) {
  return getType(target) === type
}

const create = func => {
  if (func instanceof Worker) return func;
  if (isType(func, 'string') && func.endsWith('.js')) return new Worker(func);

  if (isType(func, 'object')) {
    const injectFn = Object.values(func).reduce((def, func) => {
      return def + `  ${func},\n`
    }, '')
    const code = [
      `self.injectFn = {\n ${ injectFn }\n};\n`,
      'self.onmessage = (e) => {\n',
      '  const type = e.data.__type;\n',
      '  const result = self.injectFn[type](e.data);\n',

      '  setTimeout(() => { self.postMessage({__type: type, data: result }) }, 2000);\n',
      '  ;\n',
      '}'
    ];

    const blob = new Blob(code, { type: 'text/javascript' });
    const url = URL.createObjectURL(blob);
    const worker = new Worker(url);

    worker.cleanup = () => {
      URL.revokeObjectURL(url);
      worker.terminate();
    };

    return worker
  } else {
    console.error('参数必须是一个函数')
  }
};

const useWorker = (options, i) => {
  const worker = create(options);
  const callbackCatch = {}

  if (!worker) {
    throw new Error('Need correctly parameter!');
  }

  worker.onmessage = e => {
    const { __type, ...data } = e.data
    callbackCatch[__type].resolve(data);
  };

  worker.onerror = e => {
    if (worker.cleanup) worker.cleanup();
    callbackCatch[e.data.key].reject(e.message);

  };

  worker.onmessageerror = (e) => {
    if (worker.cleanup) worker.cleanup();
    callbackCatch[e.data.key].reject(e.message);
  };


  for (const key of Object.keys(options)) {
    worker[key] = function (data = {}) {
      data.__type = key;
      worker.postMessage(data);
      return new Promise((resolve, reject) => {
        callbackCatch[key] = { resolve, reject }
      });
    }
  }

  return worker
};

